
#include "sqlite3.h"
#include "sqlite3x.hpp"

namespace sqlite3x {

    sqlite3_connection::sqlite3_connection() : db(NULL) {}

    sqlite3_connection::sqlite3_connection(const char *db) : db(NULL) { this->open(db); }

    sqlite3_connection::sqlite3_connection(const wchar_t *db) : db(NULL) { this->open(db); }

    sqlite3_connection::~sqlite3_connection() { if(this->db) sqlite3_close(this->db); }

    void sqlite3_connection::open(const char *db) {
        if(sqlite3_open(db, &this->db)!=SQLITE_OK)
            throw database_error("unable to open database");
    }

    void sqlite3_connection::open(const wchar_t *db) {
        if(sqlite3_open16(db, &this->db)!=SQLITE_OK)
            throw database_error("unable to open database");
    }

    void sqlite3_connection::close() {
        if(this->db) {
            if(sqlite3_close(this->db)!=SQLITE_OK)
                throw database_error(*this);
            this->db=NULL;
        }
    }

    long long sqlite3_connection::insert_id() {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_last_insert_rowid(this->db);
    }

    void sqlite3_connection::set_busytimeout(int ms) {
        if(!this->db) throw database_error("database is not open");

        if(sqlite3_busy_timeout(this->db, ms)!=SQLITE_OK)
            throw database_error(*this);
    }

    void sqlite3_connection::vacuum(void)
    {
        if(!this->db) throw database_error("database is not open");
        execute_nonquery("vacuum;");
    }

    void sqlite3_connection::set_foreign_keys(bool foreign_keys_on){
        if(!this->db) throw database_error("database is not open");
        if( foreign_keys_on )
            execute_nonquery("PRAGMA foreign_keys = ON;");
        else
            execute_nonquery("PRAGMA foreign_keys = OFF;");
    }

    void sqlite3_connection::execute_nonquery(const char *sql) {
        if(!this->db) throw database_error("database is not open");
        sqlite3_command(*this, sql).execute_nonquery();
    }

    void sqlite3_connection::execute_nonquery(const wchar_t *sql) {
        if(!this->db) throw database_error("database is not open");
        sqlite3_command(*this, sql).execute_nonquery();
    }

    void sqlite3_connection::execute_nonquery(const std::string &sql) {
        if(!this->db) throw database_error("database is not open");
        sqlite3_command(*this, sql).execute_nonquery();
    }

    void sqlite3_connection::execute_nonquery(const std::wstring &sql) {
        if(!this->db) throw database_error("database is not open");
        sqlite3_command(*this, sql).execute_nonquery();
    }

    int sqlite3_connection::execute_int(const char *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_int();
    }

    int sqlite3_connection::execute_int(const wchar_t *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_int();
    }

    int sqlite3_connection::execute_int(const std::string &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_int();
    }

    int sqlite3_connection::execute_int(const std::wstring &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_int();
    }

    long long sqlite3_connection::execute_int64(const char *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_int64();
    }

    long long sqlite3_connection::execute_int64(const wchar_t *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_int64();
    }

    long long sqlite3_connection::execute_int64(const std::string &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_int64();
    }

    long long sqlite3_connection::execute_int64(const std::wstring &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_int64();
    }

    double sqlite3_connection::execute_double(const char *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_double();
    }

    double sqlite3_connection::execute_double(const wchar_t *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_double();
    }

    double sqlite3_connection::execute_double(const std::string &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_double();
    }

    double sqlite3_connection::execute_double(const std::wstring &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_double();
    }

    std::string sqlite3_connection::execute_string(const char *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_string();
    }

    std::string sqlite3_connection::execute_string(const wchar_t *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_string();
    }

    std::string sqlite3_connection::execute_string(const std::string &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_string();
    }

    std::string sqlite3_connection::execute_string(const std::wstring &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_string();
    }

    std::wstring sqlite3_connection::execute_string16(const char *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_string16();
    }

    std::wstring sqlite3_connection::execute_string16(const wchar_t *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_string16();
    }

    std::wstring sqlite3_connection::execute_string16(const std::string &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_string16();
    }

    std::wstring sqlite3_connection::execute_string16(const std::wstring &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_string16();
    }

    std::string sqlite3_connection::execute_blob(const char *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_blob();
    }

    std::string sqlite3_connection::execute_blob(const wchar_t *sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_blob();
    }

    std::string sqlite3_connection::execute_blob(const std::string &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_blob();
    }

    std::string sqlite3_connection::execute_blob(const std::wstring &sql) {
        if(!this->db) throw database_error("database is not open");
        return sqlite3_command(*this, sql).execute_blob();
    }

}
